package ncme.auto.framework.core.services.Impl.base;

import ncme.auto.framework.core.annotation.entity.Primary;
import ncme.auto.framework.core.annotation.entity.Secondary;
import ncme.auto.framework.core.annotation.entity.VerifyMultiRepetitionField;
import ncme.auto.framework.core.annotation.entity.VerifyRepetitionField;
import ncme.auto.framework.core.callback.AutoProcessControllerPart;
import ncme.auto.framework.core.entities.aspect.parameter.ServiceInfo;
import ncme.auto.framework.core.exceptions.AutoException;
import ncme.auto.framework.core.exceptions.ExceptionEnum;
import ncme.auto.framework.core.utils.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class BaseReflectService<E> extends Constants {

    @Autowired
    protected ApplicationContext applicationContext;

    public abstract void customService(AutoProcessControllerPart autoProcessControllerPart, ServiceInfo serviceInfo) throws Throwable;

    /**
     * 获取实体所有字段名
     *
     * @param entityClass 业务实体类型
     * @return 实体字段名List
     */
    protected List<String> getFieldNames(Class<?> entityClass) {
        List<String> fieldNames = new ArrayList<>();
        Field[] declaredFields = entityClass.getDeclaredFields();
        for (Field field : declaredFields) {
            String name = field.getName();
            if (!(name.equals("isDeleted") || name.equals("version")))
                fieldNames.add(field.getName());
        }
        return fieldNames;
    }

    @Override
    protected Class<?> getEntityClass() {
        return BeanUtil.getBeanGenericClassOfIndex(this.getClass(), 0);
    }

    /**
     * 从该业务实体类中获取加有某注解的字段名们
     *
     * @param <T>             业务实体类型
     * @param annotationClass 注解类型
     * @return 注解字段
     */
    protected <T extends Annotation> List<String> getFieldsWithAnnotation(Class<T> annotationClass) {
        List<String> annotationFields = new ArrayList<>();
        Field[] declaredFields = ENTITY_CLASS.getDeclaredFields();
        for (Field field : declaredFields) {
            T requiredFieldAnnotation = field.getDeclaredAnnotation(annotationClass);
            if (requiredFieldAnnotation != null) annotationFields.add(field.getName());
            else if (annotationClass.equals(VerifyMultiRepetitionField.class)) {
                if (field.getDeclaredAnnotation(Primary.class) != null || field.getDeclaredAnnotation(Secondary.class) != null)
                    annotationFields.add(field.getName());
            }
        }
        return annotationFields;
    }

    /**
     * 获取请求参数必须包含的字段名们
     *
     * @return 需要处理的字段名List
     */
    protected List<String> getRequiredFields() {
        List<String> requiredFields = new ArrayList<>();
        Field[] declaredFields = ENTITY_CLASS.getDeclaredFields();
        for (Field field : declaredFields) {
            String name = field.getName();
            if (!(name.equals("id") || name.equals("isDeleted") || name.equals("version") ||
                    name.equals("creator") || name.equals("createTime") || name.equals("editor") || name.equals("editTime")))
                requiredFields.add(field.getName());
        }
        return requiredFields;
    }

    /**
     * 获取需要单一验重的字段名们
     *
     * @return 获取需要单一验重的字段名List
     */
    protected List<String> getVerifyRepetitionFields() {
        return getFieldsWithAnnotation(VerifyRepetitionField.class);
    }

    /**
     * 获取需要组合验重的字段名们
     *
     * @return 获取需要组合验重的字段名List
     */
    protected List<String> getVerifyMultiRepetitionFields() {
        return getFieldsWithAnnotation(VerifyMultiRepetitionField.class);
    }

    /**
     * 获取对象的字段值
     *
     * @param entity    实体对象
     * @param fieldName 字段名
     * @return 字段值
     */
    protected Object getFieldValue(Object entity, String fieldName) {
        return BeanUtil.getFieldValue(entity, fieldName);
    }

    /**
     * 设置对象的字段值
     *
     * @param entity    实体对象
     * @param fieldName 字段名
     * @param value     字段值
     */
    protected void setFieldValue(Object entity, String fieldName, Object value) {
        BeanUtil.setFieldValue(entity, fieldName, value);
    }

    /**
     * 将Map转换为Entity
     *
     * @param entityClass  实体类
     * @param parameterMap 包含字段值的Map
     * @return 业务实体
     */
    public E createEntityFromMap(Class<?> entityClass, Map<String, Object> parameterMap) {
        E jdbcEntity;
        try {
            //创建空对象
            jdbcEntity = (E) entityClass.getDeclaredConstructor().newInstance();
            //为对象赋值
            Field[] declaredFields = entityClass.getDeclaredFields();
            for (Field field : declaredFields) {
                if (!field.getName().equals(""))
                    if (parameterMap.containsKey(field.getName()) && parameterMap.get(field.getName()) != null) {
                        String simpleName = parameterMap.get(field.getName()).getClass().getSimpleName();
                        switch (simpleName) {
                            case "Integer":
                                Object o = parameterMap.get(field.getName());
                                if (field.getType().getSimpleName().equals("Double")) {
                                    double v = Double.parseDouble(o.toString());
                                    setFieldValue(jdbcEntity, field.getName(), v);
                                } else {
                                    int i = Integer.parseInt(o.toString());
                                    setFieldValue(jdbcEntity, field.getName(), i);
                                }
                                break;
                            case "Timestamp":
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                String format = sdf.format(parameterMap.get(field.getName()));
                                parameterMap.replace(field.getName(), format);
                                setFieldValue(jdbcEntity, field.getName(), format);
                                break;
                            case "BigDecimal":
                                double value = ((BigDecimal) parameterMap.get(field.getName())).doubleValue();
                                parameterMap.replace(field.getName(), value);
                                setFieldValue(jdbcEntity, field.getName(), value);
                                break;
                            default:
                                setFieldValue(jdbcEntity, field.getName(), parameterMap.get(field.getName()));
                                break;
                        }
                    }
            }
            return jdbcEntity;
        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
            throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数实体和JDBC实体字段命名或类型不统一 @createEntityFromMap");
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.FIELD_VALUE, "@createEntityFromMap", e);
        }
    }

    public String getPrimary() {
        Field[] declaredFields = ENTITY_CLASS.getDeclaredFields();
        for (Field field : declaredFields) {
            Primary primaryFieldAnnotation = field.getDeclaredAnnotation(Primary.class);
            if (primaryFieldAnnotation != null) return field.getName();
        }
        return null;
        //throw new NullPointerException("@Primary 注解异常");
    }

    public String getSecondary() {
        Field[] declaredFields = ENTITY_CLASS.getDeclaredFields();
        for (Field field : declaredFields) {
            Secondary secondaryFieldAnnotation = field.getDeclaredAnnotation(Secondary.class);
            if (secondaryFieldAnnotation != null) return field.getName();
        }
        return null;
        //throw new NullPointerException("@Secondary 注解异常");
    }

}
